package com.tgy.MyFlowable.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import com.ctsi.core.common.enums.MarsExceptionEnum;
import com.ctsi.core.common.exception.MarsException;
import com.ctsi.core.common.util.$;
import com.ctsi.core.common.util.SecurityUtil;
import com.ctsi.workflow.dto.FlwInstanceDTO;
import com.ctsi.workflow.enums.FlwHandleTaskExceptionEnum;
import com.ctsi.workflow.factory.FlowableAssigneeFactory;
import com.ctsi.workflow.service.IFlwCommonService;
import com.ctsi.workflow.service.IFlwCommonTaskService;
import com.ctsi.workflow.service.IFlwDefinitionService;
import com.ctsi.workflow.service.IFlwInstanceService;
import com.ctsi.workflow.util.BpmCommentUtil;
import lombok.RequiredArgsConstructor;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 任务相关通用业务实现类
 *
 * @version 1.0
 * @author: wang xiao xiang
 * @date: 2021/8/8 19:24
 */
@Service
@RequiredArgsConstructor
public class FlwCommonTaskServiceImpl implements IFlwCommonTaskService {

    private final TaskService taskService;

    private final RuntimeService runtimeService;

    private final IFlwCommonService flwCommonService;

    private final IFlwInstanceService flwInstanceService;

    private final IFlwDefinitionService flwDefinitionService;

    private final HistoryService historyService;

    private final String FORM_DATA_VARIABLE_NAME = "formData";

    @Autowired
    private HttpServletRequest request;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void back(String taskId, String targetActId, String targetActName, String comment) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //当前节点id
        String currentActId = task.getTaskDefinitionKey();
        //获取流程实例id
        String processInstanceId = task.getProcessInstanceId();
        //获取当前操作人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //生成退回意见
        comment = BpmCommentUtil.genBackComment(name, targetActName, comment);
        //添加意见
        flwCommonService.addComment(taskId, comment);
        //获取当前操作人id
        //Long userId = MarsContextHolder.getUserId();
        Long userId = SecurityUtil.getUsername(request).getId();
        String assignee = task.getAssignee();
        if ($.isEmpty(assignee)) {
            //设置办理人为当前用户
            taskService.setAssignee(taskId, Convert.toStr(userId));
        }
        //执行退回操作
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdTo(currentActId, targetActId).changeState();
    }

    @Override
    public void turnTask(String taskId, List<String> assigneeList) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //删除其办理人及候选人候选组
        flwCommonService.deleteTaskAssignees(taskId);
        //获取要转办的人或角色的数量
        int size = assigneeList.size();
        //如果数量是1
        if (size == 1) {
            //判断是否是用户
            boolean isUser = FlowableAssigneeFactory.isUser(assigneeList.get(0));
            //如果是用户则直接设置办理人
            if (isUser) {
                taskService.setAssignee(taskId, assigneeList.get(0));
                return;
            }
        }
        //遍历
        assigneeList.forEach(userOrRoleId -> {
            //判断是否是用户
            boolean isUser = FlowableAssigneeFactory.isUser(userOrRoleId);
            //如果是用户则设置候选人
            if (isUser) {
                taskService.addCandidateUser(taskId, userOrRoleId);
            }
            //判断是否是角色
            boolean isRole = FlowableAssigneeFactory.isRole(userOrRoleId);
            if (isRole) {
                //如果是角色则设置候选组
                taskService.addCandidateGroup(taskId, userOrRoleId);
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void entrust(String taskId, String assignee, String comment) {
        //校验任务是否存在
        flwCommonService.queryTask(taskId);
        //要委托的人的姓名
        String assigneeName = FlowableAssigneeFactory.getAssigneeNameByUserId(assignee);
        //获取当前操作人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //生成委托意见
        comment = BpmCommentUtil.genEntrustComment(name, assigneeName, comment);
        //添加意见
        flwCommonService.addComment(taskId, comment);
        //执行委托操作
        taskService.delegateTask(taskId, assignee);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void jump(String taskId, String targetActId, String targetActName, String comment) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //当前节点id
        String currentActId = task.getTaskDefinitionKey();
        //获取流程实例id
        String processInstanceId = task.getProcessInstanceId();
        //获取当前操作人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //生成跳转意见
        comment = BpmCommentUtil.genJumpComment(name, targetActName, comment);
        //添加意见
        flwCommonService.addComment(taskId, comment);
        //执行跳转操作
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdTo(currentActId, targetActId).changeState();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void end(String taskId, String comment) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //获取流程实例id
        String processInstanceId = task.getProcessInstanceId();
        //获取当前操作人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //生成终止意见
        comment = BpmCommentUtil.genEndComment(name, comment);
        //添加意见
        flwCommonService.addComment(taskId, comment);
        //获取当前操作人id
        //Long userId = MarsContextHolder.getUserId();
        Long userId = SecurityUtil.getUsername(request).getId();
        String assignee = task.getAssignee();
        if ($.isEmpty(assignee)) {
            //设置办理人为当前用户
            taskService.setAssignee(taskId, Convert.toStr(userId));
        }
        //结束流程
        runtimeService.deleteProcessInstance(processInstanceId, comment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void suspend(String taskId) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //获取流程实例id
        String processInstanceId = task.getProcessInstanceId();
        //挂起流程
        FlwInstanceDTO flwInstanceDTO = new FlwInstanceDTO();
        flwInstanceDTO.setId(processInstanceId);
        flwInstanceService.activeOrSuspend(flwInstanceDTO, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSign(String taskId, List<String> assigneeList, String comment) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        //流程定义id
        String processDefinitionId = task.getProcessDefinitionId();
        //流程实例id
        String processInstanceId = task.getProcessInstanceId();
        //当前活动节点id
        String currentActId = task.getTaskDefinitionKey();
        //当前活动节点名称（任务名称）
        String currentActName = task.getName();
        //多实例用户任务节点的元素变量名
        String multiInstanceActAssigneeParam = flwDefinitionService
                .getMultiInstanceActAssigneeParam(processDefinitionId, currentActId);
        //如果元素变量名为空则表示该节点不是会签节点
        if ($.isEmpty(multiInstanceActAssigneeParam)) {
            throw new MarsException(FlwHandleTaskExceptionEnum.TASK_ADD_SIGN_ERROR);
        }
        //加签人的姓名
        List<String> assigneeNameList = CollectionUtil.newArrayList();
        //遍历要加签的人
        assigneeList.forEach(assignee -> {
            //获取加签人名称
            String assigneeName = FlowableAssigneeFactory.getAssigneeNameByUserId(assignee);
            assigneeNameList.add(assigneeName);
            //定义参数
            Map<String, Object> assigneeVariables = CollectionUtil.newHashMap();
            //根据获取的变量名加参数
            assigneeVariables.put(multiInstanceActAssigneeParam, assignee);
            //执行加签操作
            try {
                runtimeService.addMultiInstanceExecution(currentActId, processInstanceId, assigneeVariables);
            } catch (FlowableException e) {
                //抛异常加签失败
                throw new MarsException(FlwHandleTaskExceptionEnum.TASK_ADD_SIGN_ERROR);
            } catch (Exception e) {
                //否则的话，可能出现服务器内部异常
                e.printStackTrace();
                throw new MarsException(MarsExceptionEnum.SERVER_ERROR);
            }
        });
        //当前办理人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //生成加签意见（此处在加签后添加意见，无影响）
        comment = BpmCommentUtil.genAddSignComment(name, assigneeNameList, currentActName, comment);
        //保存意见
        flwCommonService.addComment(taskId, comment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSign(String taskId, List<String> assigneeList, String comment) {
        //校验任务是否存在
        Task task = flwCommonService.queryTask(taskId);
        String processInstanceId = task.getProcessInstanceId();
        //当前活动节点名称（任务名称）
        String currentActName = task.getName();
        //当前办理人姓名
        String name = SecurityUtil.getUsername(request).getAccount();
        //减签人的姓名
        List<String> assigneeNameList = CollectionUtil.newArrayList();
        //遍历要加签的人
        assigneeList.forEach(assignee -> {
            //获取减签人名称
            String assigneeName = FlowableAssigneeFactory.getAssigneeNameByUserId(assignee);
            assigneeNameList.add(assigneeName);
        });
        //生成减签意见
        comment = BpmCommentUtil.genDeleteSignComment(name, assigneeNameList, currentActName, comment);
        //保存意见
        flwCommonService.addComment(taskId, comment);
        //根据processInstanceId查询任务
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        for (Task taskInfo : taskList) {
            if (assigneeList.contains(taskInfo.getAssignee())) {
                //执行减签操作并完成
                try {
                    runtimeService.deleteMultiInstanceExecution(taskInfo.getExecutionId(), true);
                } catch (FlowableException e) {
                    //抛异常减签失败
                    throw new MarsException(FlwHandleTaskExceptionEnum.TASK_DELETE_SIGN_ERROR);
                } catch (Exception e) {
                    //否则的话，可能出现服务器内部异常
                    e.printStackTrace();
                    throw new MarsException(MarsExceptionEnum.SERVER_ERROR);
                }
            }
        }
    }

    @Override
    public Map<String, Object> taskData(String taskId) {
        Map<String, Object> variables = CollectionUtil.newHashMap();
        //获取运行中的任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        //如果运行中的任务不存在，则表示任务已结束，通过historyService获取
        if ($.isNull(task)) {
            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
            //如果历史的任务也不存在，则抛异常
            if ($.isNull(historicTaskInstance)) {
                throw new MarsException(FlwHandleTaskExceptionEnum.TASK_NOT_EXIST);
            }
            //获取流程实例id
            String processInstanceId = historicTaskInstance.getProcessInstanceId();
            //获取其历史变量集合
            List<HistoricVariableInstance> historicVariableInstanceList = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId)
                    .list();
            historicVariableInstanceList.forEach(historicVariableInstance -> {
                if (FORM_DATA_VARIABLE_NAME.equals(historicVariableInstance.getVariableName())) {
                    variables.put(historicVariableInstance.getVariableName(), historicVariableInstance.getValue());
                }
            });
        } else {
            //获取流程实例id
            String processInstanceId = task.getProcessInstanceId();
            Map<String, Object> runtimeVariables = runtimeService.getVariables(processInstanceId);
            runtimeVariables.forEach((key, value) -> {
//                if (FORM_DATA_VARIABLE_NAME.equals(key)) {
                    variables.put(key, value);
//                }
            });
        }
        return variables;
    }
}
